package cn.uncode.baas.server.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;

import cn.uncode.dal.cache.CacheManager;
import cn.uncode.dal.descriptor.QueryResult;
import cn.uncode.dal.utils.JsonUtils;
import cn.uncode.baas.server.acl.token.AccessToken;
import cn.uncode.baas.server.acl.token.DefaultAccessToken;
import cn.uncode.baas.server.cache.SystemCache;
import cn.uncode.baas.server.constant.Resource;
import cn.uncode.baas.server.dto.RestApp;
import cn.uncode.baas.server.dto.RestUser;
import cn.uncode.baas.server.dto.RestUserAcl;
import cn.uncode.baas.server.exception.ValidateException;
import cn.uncode.baas.server.internal.context.RestContextManager;
import cn.uncode.baas.server.internal.message.Messages;
import cn.uncode.baas.server.internal.module.data.DataParamResolve;
import cn.uncode.baas.server.internal.module.mail.IMailModule;
import cn.uncode.baas.server.service.IGenericService;
import cn.uncode.baas.server.service.IResterService;
import cn.uncode.baas.server.service.IUserService;
import cn.uncode.baas.server.utils.DataUtils;
import cn.uncode.baas.server.utils.MD5Utils;
import cn.uncode.baas.server.utils.PropertiesUtil;
import cn.uncode.baas.server.utils.RandUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class UserService implements IUserService {

	@Autowired
	IGenericService genericService;
	
	@Autowired
    private CacheManager cacheManager;
	
	@Autowired
	private IMailModule mailModule;
	
	@Autowired
	private IResterService resterService;
	
	public String signup(Map<String, Object> param) throws ValidateException, Exception{
		User user = buildUser(param);
		if(StringUtils.isEmpty(user.getUsername())){
			throw new ValidateException(Messages.getString("ValidateError.1", "username"));
		}
		if(StringUtils.isEmpty(user.getPassword())){
			throw new ValidateException(Messages.getString("ValidateError.1", "password")); 
		}
		DataParamResolve dataParam = new DataParamResolve(param);
		Map<String, Object> params = new HashMap<String, Object>();
		params.put(user.getUsernameKey(), user.getUsername());
		int count = genericService.countByCriteria(params, user.getTable(), -1, user.getDatabase());
		if(count > 0){
			throw new ValidateException(Messages.getString("ValidateError.6", user.getUsername()));
		}
		param.put(user.getPasswordKey(), MD5Utils.encrypt(user.getPassword()));
		if(!user.isEmailFlag()){
			param.put(user.getStatusKey(), Resource.REST_USER_STATUS_VALID);
		}
		Object id = genericService.insert(dataParam.getParams(), user.getTable(), user.getDatabase());
		RestUser restUser = SystemCache.getRestUser(RestContextManager.getContext().getBucket());
		if(StringUtils.isNotEmpty(restUser.getDefaultGroup())){
			resterService.insertRestUserAcl(RestContextManager.getContext().getBucket(), user.getUsername(), restUser.getDefaultGroup(), null);
		}
		//email
		if(user.isEmailFlag()){
			user.setId(String.valueOf(id));
			Map<String, Object> paramEmail = buildMailParams(user, EMAIL_ACTIVATE);
			mailModule.sendMail(paramEmail);
		}
		return String.valueOf(id);
	}
	
	/**
	 * build mail validate code
	 * @param user
	 * @param url
	 * @param type
	 * @return
	 */
	private String buildSendMailCodeKey(String id, String type){
		String code = RandUtils.generationRandomString(20, RandUtils.ENGLISH_NUMBER);
		StringBuffer key = new StringBuffer("mail_code_");
		key.append(RestContextManager.getContext().getBucket()).append("_").append(code);
		if(EMAIL_ACTIVATE.equals(type)){
			key.append("_").append(EMAIL_ACTIVATE);
		}else if(EMAIL_RESET.equals(type)){
			key.append("_").append(EMAIL_RESET);
		}
		cacheManager.getCache().putObject(key.toString(), id, 60*30);
		return code;
	}
	
	private String buildReceiveMailCodeKey(String code, String type){
		StringBuffer key = new StringBuffer("mail_code_");
		key.append(RestContextManager.getContext().getBucket()).append("_").append(code);
		if(EMAIL_ACTIVATE.equals(type)){
			key.append("_").append(EMAIL_ACTIVATE);
		}else if(EMAIL_RESET.equals(type)){
			key.append("_").append(EMAIL_RESET);
		}
		return key.toString();
	}
	
	/**
	 * build mail parameters
	 * @param user
	 * @param url
	 * @param type
	 * @return
	 */
	private  Map<String, Object> buildMailParams(User user, String type) throws ValidateException{
		String mailContent = null;
		RestApp app = SystemCache.getRestApp(RestContextManager.getContext().getBucket());
		String code = buildSendMailCodeKey(user.getId(), type);
		if(EMAIL_ACTIVATE.equals(type)){
			mailContent = buildActivateMailContent(user, code);
		}else if(EMAIL_RESET.equals(type)){
			mailContent = buildResetPassMailContent(user, code);
		}else{
			throw new ValidateException(Messages.getString("ValidateError.22"));
		}
		
		Map<String, Object> paramEmail = new HashMap<String, Object>();
		paramEmail.put("service", PropertiesUtil.getPropertisValue("email.service"));
		paramEmail.put("port", PropertiesUtil.getPropertisValue("email.port"));
		Map<String, Object> auth = new HashMap<String, Object>();
		auth.put("user", PropertiesUtil.getPropertisValue("email.user"));
		auth.put("pass", PropertiesUtil.getPropertisValue("email.pass"));
		paramEmail.put("auth", auth);
		paramEmail.put("from", PropertiesUtil.getPropertisValue("email.user"));
		paramEmail.put("to", user.getEmail());
		paramEmail.put("subject", app.getName()+"用户认证中心");
		paramEmail.put("html", mailContent);
		return paramEmail;
	}
	
	/**
	 * 
	 * @param user
	 * @param validateCode
	 * @param loginUrl
	 * @return
	 */
	private String buildResetPassMailContent(User user, String validateCode){
		String bucket = RestContextManager.getContext().getBucket();
		RestApp app = SystemCache.getRestApp(bucket);
		StringBuffer sb = new StringBuffer();
		sb.append("<!DOCTYPE html PUBLIC").append("-//W3C//DTD XHTML 1.0 Transitional//EN")
	        .append("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
	        .append("<html xmlns=\"http://www.w3.org/1999/xhtml\"> <head> <meta")
	        .append("http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"")
	        .append("/> <title>").append(app.getName()).append("用户安全中心</title> </head> <body><div style=")
	        .append("width:588px; font:normal 14px/1.6em simsun,Tahoma, Verdana, Lucida, Arial,")
	        .append("Helvetica, sans-serif;color:#333333;background:url(http://   .png)")
	        .append("no-repeat left bottom;><div style=\"padding:2px 20px  30px;\" >").append("<p>")
	        .append("亲爱的<span style=\"color:#C40000\" >" + user.getUsername() + "</span> , 您好")
	        .append("</p>").append("<p>").append("请点击这里，重置您的密码： <br />")
	        .append("<a href=\"").append("http://rest.uncode.cn/").append(RestContextManager.getContext().getBucket()).append("/resetpass").append("?username=")
	        .append(user.getEmail() + "&code=" + validateCode + "\"").append("title=\"请点击这里，重置您的密码：\" target=\"_blank\"")
	        .append(">").append("http://rest.uncode.cn/").append(RestContextManager.getContext().getBucket()).append("/resetpass")
	        .append("?username=" + user.getEmail() + "&code=" + validateCode + "</a> <br />")
	        .append("<span class=\"c_gray\">(如果链接无法点击，请将它拷贝到浏览器的地址栏中，有效时间30分钟)</span>").append("</p>").append("<p>")
	        .append("好的密码，不但应该容易记住，还要尽量符合以下强度标准： <br />").append("·包含大小写字母、数字和符号 <br />")
	        .append("·不少于 10 位 <br />").append("·不包含生日、手机号码等易被猜出的信息</p><p>").append("<br />")
	        .append("<br />").append("该链接将在您修改密码后失效。").append("</p>").append("<p>")
	        .append(app.getName()).append("安全中心宗旨：竭尽全力为您的帐号安全保驾护航！ <br />")
	        .append("<p style=\"text-align:right;\">").append("<br />").append(app.getName()).append("安全中心 敬启").append("</p>")
	        .append("<p>").append("<br />").append("</p>").append("</div> </div> </body> </html>");
		return sb.toString();
	}
	
	/**
	 * 
	 * @param user
	 * @param validateCode
	 * @param originUrl
	 * @return
	 */
	private String buildActivateMailContent(User user, String validateCode){
		String bucket = RestContextManager.getContext().getBucket();
		RestApp app = SystemCache.getRestApp(bucket);
		StringBuffer sb = new StringBuffer("<!DOCTYPE html PUBLIC");
		sb.append("-//W3C//DTD XHTML 1.0 Transitional//EN")
        .append("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
        .append("<html xmlns=\"http://www.w3.org/1999/xhtml\"> <head> <meta")
        .append("http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"")
        .append("/> <title>").append(app.getName()).append("用户安全中心   </title> </head>").append("<body> <div style=")
        .append("width:588px; font:normal 14px/1.6em simsun,Tahoma, Verdana, Lucida, Arial,")
        .append("Helvetica, sans-serif;color:#333333;background:url(http// xx.png)")
        .append("no-repeat left bottom; > <div style=\"padding:2px 20px  30px;\" >").append("<p>")
        .append("亲爱的<span style=\"color:#C40000\" >" + user.getUsername() + "</span> , 您好")
        .append("</p>").append("<p>").append("请点击这里，激活您的").append(app.getName()).append("账户： <br />")
        .append("<a href=\"").append("http://rest.uncode.cn/").append(RestContextManager.getContext().getBucket()).append("/activate").append("?username=")
        .append(user.getEmail() + "&code=" + validateCode + "\"")
        .append("title=\"请点击这里，激活您的").append(app.getName()).append("账户：\" target=\"_blank\"")
        .append(">").append("http://rest.uncode.cn/").append(RestContextManager.getContext().getBucket()).append("/activate")
        .append("?username=" + user.getEmail() + "&code=" + validateCode + "</a> <br />")
        .append("<span class=\"c_gray\">(如果链接无法点击，请将它拷贝到浏览器的地址栏中)</span>").append("</p>").append("<p>")
        .append("该链接将在您激活账户后失效。").append("</p>").append("<p>").append(app.getName()).append("安全中心宗旨：竭尽全力为您的帐号安全保驾护航！ <br />")
        .append("</p>").append("</div> </div> </body> </html>");
		return sb.toString();
	}

	public String login(Map<String, Object> param) throws ValidateException, Exception {
		User user = buildUser(param);
		
		if(StringUtils.isEmpty(user.getUsername())){
			throw new ValidateException(Messages.getString("ValidateError.1", "username"));
		}
		if(StringUtils.isEmpty(user.getPassword())){
			throw new ValidateException(Messages.getString("ValidateError.1", "password")); 
		}
		String tokenKey = buildAccessTokenCacheKey(RestContextManager.getContext().getBucket(), user.getUsername());
		Object tokenId = cacheManager.getCache().getObject(tokenKey);
		AccessToken accessToken = null;
		if(null != tokenId){
			accessToken = (AccessToken) cacheManager.getCache().getObject(String.valueOf(tokenId));
		}
		if(accessToken != null && !accessToken.isExpired()){
			return JsonUtils.objToJson(accessToken);
		}
		Map<String, Object> params = new HashMap<String, Object>();
		params.put(user.getUsernameKey(), user.getUsername());
		QueryResult queryResult = genericService.selectByCriteria(null, params, user.getTable(), -1, user.getDatabase());
		Map<String, Object> obj = queryResult.get();
		if(obj == null || obj.size() == 0){
			throw new ValidateException(Messages.getString("ValidateError.7", user.getUsername()));
		}
		if(obj.containsKey(user.getPasswordKey())){
			String md5 = MD5Utils.encrypt(user.getPassword());
			String pwd = String.valueOf(obj.get(user.getPasswordKey()));
			if(!md5.equals(pwd)){
				throw new ValidateException(Messages.getString("ValidateError.8"));
			}
		}
		if(obj.containsKey(user.getStatusKey()) && null != obj.get(user.getStatusKey())){
			int status = Integer.parseInt(String.valueOf(obj.get(user.getStatusKey())));
			if(status == Resource.REST_USER_STATUS_INVALID){
				throw new ValidateException(Messages.getString("ValidateError.18"));
			}
		}
		//acl
		List<String>  roles = null;
		List<String>  groups = new ArrayList<String>();
		RestUserAcl acl = resterService.loadRestUserAcl(RestContextManager.getContext().getBucket(), user.getUsername());
		if(null != acl){
			if(StringUtils.isNotEmpty(acl.getGroups())){
				groups.addAll(Arrays.asList(acl.getGroups().split(",")));
				roles = resterService.loadRestRolesFromGroup(RestContextManager.getContext().getBucket(), acl.getGroups());
			}
			if(roles == null){
				roles = new ArrayList<String>();
			}
			if(StringUtils.isNotEmpty(acl.getRoles())){
				roles.addAll(Arrays.asList(acl.getRoles().split(",")));
			}
		}
		
		//access token
		accessToken = new DefaultAccessToken(RestContextManager.getContext().getBucket(), 
				user.getUsername(), UUID.randomUUID().toString() ,groups ,roles);
		
		if(obj.containsKey("id") && null != obj.get("id")){
			accessToken.getAdditionalInformation().put("id", obj.get("id"));
		}
		cacheManager.getCache().putObject(buildAccessTokenCacheKey(RestContextManager.getContext().getBucket(), user.getUsername()), 
				accessToken.getValue(), Resource.ACCESS_TOKEN_EXPIRATION_TIME);
		cacheManager.getCache().putObject(accessToken.getValue(), accessToken, Resource.ACCESS_TOKEN_EXPIRATION_TIME);
		return JsonUtils.objToJson(accessToken);
	}

	public int update(Map<String, Object> param)throws ValidateException, Exception {
		User user = buildUser(param);
		if(StringUtils.isNotBlank(user.getUsername())){
			param.remove(user.getPasswordKey());
		}
		// id or user name is null
		if(!param.containsKey("id") && !param.containsKey(user.getUsernameKey())){
			throw new ValidateException(Messages.getString("ValidateError.1", "id or username"));
		}
		// query object
		QueryResult queryResult  = null;
		if(param.containsKey("id")){
			int id = Integer.valueOf(String.valueOf(param.get("id")));
			queryResult = genericService.selectByPrimaryKey(null, id, user.getTable(), -1, user.getDatabase());
		}else{
			Map<String, Object> params = new HashMap<String, Object>();
			params.put(user.getUsernameKey(), user.getUsername());
			queryResult = genericService.selectByCriteria(null, params, user.getTable(), -1, user.getDatabase());
		}
		//user must be exist
		Map<String, Object> userMap = queryResult.get();
		if(userMap == null || userMap.size() == 0){
			throw new ValidateException(Messages.getString("ValidateError.7", user.getUsername()));
		}
		int id = Integer.valueOf(String.valueOf(userMap.get("id")));
		// check user login status
		boolean check = false;
		String username = String.valueOf(userMap.get(user.getUsernameKey()));
		AccessToken accessToken = getAccessToken4LoginWithUserName(username);
		//user is not login
		if(null == accessToken || accessToken.isExpired()){
			//check code
			if(!param.containsKey(Resource.REQ_EMAIL_CODE)){
				throw new ValidateException(Messages.getString("ValidateError.19", user.getUsername()));
			}
			String code = String.valueOf(param.get(Resource.REQ_EMAIL_CODE));
			String emailType = user.getEmailType();
			if(StringUtils.isEmpty(emailType)){
				emailType = EMAIL_RESET;
			}
			String key = buildReceiveMailCodeKey(code, emailType);
			Object idObj = cacheManager.getCache().getObject(key);
			if(null == idObj){
				throw new ValidateException(Messages.getString("ValidateError.21", user.getUsername()));
			}
			Integer tempId = (Integer)idObj;
			if(tempId != id){
				throw new ValidateException(Messages.getString("ValidateError.20"));
			}
			cacheManager.getCache().removeObject(key);
			param.remove(Resource.REQ_EMAIL_CODE);
			check = true;
		}else{
			check = true;
		}
		if(!check){
			throw new ValidateException(Messages.getString("ValidateError.23"));
		}
		// handle password	
		if(StringUtils.isNotBlank(user.getPassword())){
			String enterOld = String.valueOf(param.get(Resource.REST_USER_OLD_PASSWORD));
			enterOld = MD5Utils.encrypt(enterOld);
			String old = String.valueOf(userMap.get(user.getPasswordKey()));
			if(!old.equals(enterOld)){
				throw new ValidateException(Messages.getString("ValidateError.9"));
			}
			param.remove(Resource.REST_USER_OLD_PASSWORD);
			param.put(user.getPasswordKey(), MD5Utils.encrypt(user.getPassword()));
		}
		// handle status
		if(user.getStatus() != null){
			Integer old = Integer.valueOf(String.valueOf(userMap.get(user.getStatusKey())));
			if(old == Resource.REST_USER_STATUS_INVALID){
				//continue
			}else{
				param.remove(user.getStatusKey());
			}
		}
		// update
		int result = genericService.updateByPrimaryKey(id, param, user.getTable(), user.getDatabase());
		return result;
	}

	private AccessToken getAccessToken4LoginWithUserName(String username) {
		String tokenKey = buildAccessTokenCacheKey(RestContextManager.getContext().getBucket(), username);
		Object value = cacheManager.getCache().getObject(tokenKey);
		if(null != value){
			String tokenValue = String.valueOf(value);
			value = cacheManager.getCache().getObject(tokenValue);
			if(null != value){
				return (AccessToken)value;
			}
		}
		return null;
	}


	public Map<String, Object> getUser(Map<String, Object> param) {
		// query object
		Map<String, Object> map = DataUtils.convert2Map(param);
		User user = buildUser(map);
		QueryResult queryResult  = null;
		if(map.containsKey("id")){
			int id = Integer.valueOf(String.valueOf(map.get("id")));
			queryResult = genericService.selectByPrimaryKey(null, id, user.getTable(), -1, user.getDatabase());
		}else{
			Map<String, Object> params = new HashMap<String, Object>();
			params.put(user.getUsernameKey(), user.getUsername());
			queryResult = genericService.selectByCriteria(null, params, user.getTable(), -1, user.getDatabase());
		}
		return queryResult.get();
	}
	
	public void logout(Map<String, Object> param) {
		if(param.containsKey(Resource.REQ_ACCESS_TOKEN)){
			String tokenId = String.valueOf(param.get(Resource.REQ_ACCESS_TOKEN));
			if(StringUtils.isNotBlank(tokenId)){
				AccessToken accessToken = (AccessToken) cacheManager.getCache().getObject(tokenId);
				if(accessToken != null){
					String user = String.valueOf(accessToken.getAdditionalInformation().get(AccessToken.USER));
					String tokenKey = buildAccessTokenCacheKey(RestContextManager.getContext().getBucket(), user);
					cacheManager.getCache().removeObject(tokenKey);
				}
				cacheManager.getCache().removeObject(tokenId);
			}
		}
	}
	
	public boolean checkToken(Map<String, Object> param) {
		Map<String, Object> map = DataUtils.convert2Map(param);
		if(map.containsKey(Resource.REQ_ACCESS_TOKEN)){
			String tokenId = String.valueOf(map.get(Resource.REQ_ACCESS_TOKEN));
			if(StringUtils.isNotBlank(tokenId)){
				AccessToken accessToken = (AccessToken) cacheManager.getCache().getObject(tokenId);
				if(accessToken != null && !accessToken.isExpired()){
					return true;
				}
			}
		}
		return false;
	}
	
	public void sendMailAgain(Map<String, Object> param)throws ValidateException{
		User buildUser = buildUser(param);
		// id or user name is null
		if(!param.containsKey("id") && !param.containsKey(buildUser.getUsernameKey())){
			throw new ValidateException(Messages.getString("ValidateError.1", "id or username"));
		}
		// query object
		QueryResult queryResult  = null;
		if(param.containsKey("id")){
			int id = Integer.valueOf(String.valueOf(param.get("id")));
			queryResult = genericService.selectByPrimaryKey(null, id, buildUser.getTable(), -1, buildUser.getDatabase());
		}else{
			Map<String, Object> params = new HashMap<String, Object>();
			params.put(buildUser.getUsernameKey(), buildUser.getUsername());
			queryResult = genericService.selectByCriteria(null, params, buildUser.getTable(), -1, buildUser.getDatabase());
		}
		//user must be exist
		Map<String, Object> userMap = queryResult.get();
		if(userMap == null || userMap.size() == 0){
			throw new ValidateException(Messages.getString("ValidateError.7", buildUser.getUsername()));
		}
		User user = buildUser(userMap);
		user.setEmailType(buildUser.getEmailType());
		user.setLink(buildUser.getLink());
		Object id = Integer.valueOf(String.valueOf(userMap.get("id")));
		user.setId(String.valueOf(id));
		Map<String, Object> paramEmail = buildMailParams(user, user.getEmailType());
		mailModule.sendMail(paramEmail);
	}
	
	/**
	 * 
	 * @param map
	 * @return
	 */
	private User buildUser(Map<String, Object> map) {
		User user = new User();
		String bucket = RestContextManager.getContext().getBucket();
		RestUser restUser = SystemCache.getRestUser(bucket);
		if(restUser != null && StringUtils.isNotBlank(restUser.getUsernameField()) && null != map.get(restUser.getUsernameField())){
			user.setUsername(String.valueOf(map.get(restUser.getUsernameField())));
			user.setUsernameKey(restUser.getUsernameField());
		}else{
			if(null != map.get(Resource.REST_USER_USERNAME)){
				user.setUsername(String.valueOf(map.get(Resource.REST_USER_USERNAME)));
				user.setUsernameKey(Resource.REST_USER_USERNAME);
			}
		}
		if(restUser != null && StringUtils.isNotBlank(restUser.getPasswordField()) && null != map.get(restUser.getPasswordField())){
			user.setPassword(String.valueOf(map.get(restUser.getPasswordField())));
			user.setPasswordKey(restUser.getPasswordField());
		}else{
			if(null != map.get(Resource.REST_USER_PASSWORD)){
				user.setPassword(String.valueOf(map.get(Resource.REST_USER_PASSWORD)));
				user.setPasswordKey(Resource.REST_USER_PASSWORD);
			}
		}
		if(restUser != null && StringUtils.isNotBlank(restUser.getEmailField()) && null != map.get(restUser.getEmailField())){
			user.setEmail(String.valueOf(map.get(restUser.getEmailField())));
			user.setEmailKey(restUser.getEmailField());
		}else{
			if(null != map.get(Resource.REST_USER_EMAIL)){
				user.setEmail(String.valueOf(map.get(Resource.REST_USER_EMAIL)));
				user.setEmailKey(Resource.REST_USER_EMAIL);
			}
		}
		if(restUser != null && StringUtils.isNotBlank(restUser.getMobileField()) && null != map.get(restUser.getMobileField())){
			user.setMobile(String.valueOf(map.get(restUser.getMobileField())));
			user.setMobileKey(restUser.getMobileField());
		}else{
			if(null != map.get(Resource.REST_USER_MOBILE)){
				user.setMobile(String.valueOf(map.get(Resource.REST_USER_MOBILE)));
				user.setMobileKey(Resource.REST_USER_MOBILE);
			}
		}
		if(restUser != null && StringUtils.isNotBlank(restUser.getStatusField()) && null != map.get(restUser.getStatusField())) {
			user.setStatusKey(restUser.getStatusField());
		}else{
			if(null != map.get(Resource.REST_USER_STATUS))
				user.setStatusKey(Resource.REST_USER_STATUS);
		}
		if(null != map && map.size() > 0){
			if(restUser != null && restUser.getEmailAuth() == Resource.REST_USER_EMAIL_AUTH_YES){
				user.setStatus(Resource.REST_USER_STATUS_INVALID);
				user.setEmailFlag(true);
			}else{
				user.setStatus(Resource.REST_USER_STATUS_VALID);
			}
			if(restUser != null && StringUtils.isNotBlank(restUser.getStatusField())) {
				user.setStatusKey(restUser.getStatusField());
			}
		}
		if(restUser != null){
			user.setTable(restUser.getTableName());
		}
		
		RestApp app = SystemCache.getRestApp(bucket);
		user.setDatabase(app.getDatabase());
		
		if(StringUtils.isEmpty(user.getTable())){
			if(user.getUsername().equals(app.getUser())){
				user.setDatabase("rest");
				user.setTable("userinfo");
			}else{
				throw new ValidateException(Messages.getString("ValidateError.1", "table")); 
			}
		}
		
		/*if(!map.containsKey(DataParamResolve.FIELD_TABLE)){
			map.put(DataParamResolve.FIELD_TABLE, user.getTable());
		}*/
		if(map.containsKey(Resource.REQ_USER_LINK_KYE)){
			user.setLink(String.valueOf(map.get(Resource.REQ_USER_LINK_KYE)));
			map.remove(Resource.REQ_USER_LINK_KYE);
		}
		if(map.containsKey(Resource.REST_USER_EMAIL_TYPE)){
			user.setEmailType(String.valueOf(map.get(Resource.REST_USER_EMAIL_TYPE)));
			map.remove(Resource.REST_USER_EMAIL_TYPE);
		}
		return user;
	}
	
	private String buildAccessTokenCacheKey(String bucket, String username){
		return Resource.ACCESS_TOKEN_CACHE_KEY_PREFIX + bucket + "_" + username;
	}
	
	public boolean checkUsername(Map<String, Object> param) throws ValidateException{
		User user = buildUser(param);
		Map<String, Object> params = new HashMap<String, Object>();
		params.put(user.getUsernameKey(), user.getUsername());
		int count = genericService.countByCriteria(params, user.getTable(), -1, user.getDatabase());
		if(count > 0){
			throw new ValidateException(Messages.getString("ValidateError.6", user.getUsername()));
		}
		return true;
	}
	
	public Map<String, Object> getToken(Map<String, Object> param){
		Map<String, Object> map = DataUtils.convert2Map(param);
		if(map.containsKey(Resource.REQ_ACCESS_TOKEN)){
			String tokenId = String.valueOf(map.get(Resource.REQ_ACCESS_TOKEN));
			if(StringUtils.isNotBlank(tokenId)){
				AccessToken accessToken = (AccessToken) cacheManager.getCache().getObject(tokenId);
				if(accessToken != null && !accessToken.isExpired()){
					return (Map<String, Object>) JsonUtils.objToMap(accessToken);
				}
			}
		}
		return null;
	}
	
	public AccessToken getToken(String token){
		if(StringUtils.isNotBlank(token)){
			AccessToken accessToken = (AccessToken) cacheManager.getCache().getObject(token);
			return accessToken;
		}
		return null;
	}
	
	@Override
	public List<Map<String, Object>> selectUsers(Map<String, Object> param) {
		// query object
		User user = buildUser(param);
		QueryResult queryResult  = null;
		if(StringUtils.isNotEmpty(user.getId())){
			param.remove("id");
		}
		if(StringUtils.isNotEmpty(user.getUsername())){
			param.remove(Resource.REST_USER_USERNAME);
			param.put(user.getUsernameKey(), user.getUsername());
		}
		if(StringUtils.isNotEmpty(user.getEmail())){
			param.remove(Resource.REST_USER_EMAIL);
			param.put(user.getEmailKey(), user.getEmail());
		}
		if(null != user.getStatus()){
			param.remove(Resource.REST_USER_STATUS);
			param.put(user.getStatusKey(), user.getStatus());
		}
		if(StringUtils.isNotEmpty(user.getMobile())){
			param.remove(Resource.REST_USER_MOBILE);
			param.put(user.getMobileKey(), user.getMobile());
		}
		queryResult = genericService.selectByCriteria(null, param, user.getTable(), -1, user.getDatabase());
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		if(null != queryResult && null != queryResult.getList()){
			for(Map<String, Object> item:queryResult.getList()){
				Map<String, Object> map = new HashMap<String, Object>();
				if(StringUtils.isNotEmpty(user.getUsernameKey())){
					if(item.containsKey(user.getUsernameKey())){
						map.put(Resource.REST_USER_USERNAME, item.get(user.getUsernameKey()));
					}
				}else{
					map.put(Resource.REST_USER_USERNAME, item.get(Resource.REST_USER_USERNAME));
				}
				if(StringUtils.isNotEmpty(user.getEmailKey())){
					if(item.containsKey(user.getEmailKey())){
						map.put(Resource.REST_USER_PASSWORD, item.get(user.getEmailKey()));
					}
				}else{
					map.put(Resource.REST_USER_PASSWORD, item.get(Resource.REST_USER_PASSWORD));
				}
				if(StringUtils.isNotEmpty(user.getStatusKey())){
					if(item.containsKey(user.getStatusKey())){
						map.put(Resource.REST_USER_STATUS, item.get(user.getStatusKey()));
					}
				}else{
					map.put(Resource.REST_USER_STATUS, item.get(Resource.REST_USER_STATUS));
				}
				if(StringUtils.isNotEmpty(user.getMobileKey())){
					if(item.containsKey(user.getMobileKey())){
						map.put(Resource.REST_USER_MOBILE, item.get(user.getMobileKey()));
					}
				}else{
					map.put(Resource.REST_USER_MOBILE, item.get(Resource.REST_USER_MOBILE));
				}
				map.put("id", item.get("id"));
				list.add(map);
			}
		}
		return list;
	}
	
	class User{
		
		private String database;
		private String table;
		private String username;
		private String usernameKey;
		private String password;
		private String passwordKey;
		private String statusKey;
		private Integer status;
		private boolean emailFlag;
		private String email;
		private String emailKey;
		private String mobile;
		private String mobileKey;
		private String id;
		private String link;
		private String emailType;
		
		public String getTable() {
			return table;
		}
		public void setTable(String table) {
			this.table = table;
		}
		public String getUsername() {
			return username;
		}
		public void setUsername(String username) {
			this.username = username;
		}
		public String getPassword() {
			return password;
		}
		public void setPassword(String password) {
			this.password = password;
		}
		public String getPasswordKey() {
			return passwordKey;
		}
		public void setPasswordKey(String passwordKey) {
			this.passwordKey = passwordKey;
		}
		public String getUsernameKey() {
			return usernameKey;
		}
		public void setUsernameKey(String usernameKey) {
			this.usernameKey = usernameKey;
		}
		public String getStatusKey() {
			return statusKey;
		}
		public void setStatusKey(String statusKey) {
			this.statusKey = statusKey;
		}
		public Integer getStatus() {
			return status;
		}
		public void setStatus(Integer status) {
			this.status = status;
		}
		public boolean isEmailFlag() {
			return emailFlag;
		}
		public void setEmailFlag(boolean emailFlag) {
			this.emailFlag = emailFlag;
		}
		public String getEmail() {
			return email;
		}
		public void setEmail(String email) {
			this.email = email;
		}
		public String getEmailKey() {
			return emailKey;
		}
		public void setEmailKey(String emailKey) {
			this.emailKey = emailKey;
		}
		public String getMobile() {
			return mobile;
		}
		public void setMobile(String mobile) {
			this.mobile = mobile;
		}
		public String getMobileKey() {
			return mobileKey;
		}
		public void setMobileKey(String mobileKey) {
			this.mobileKey = mobileKey;
		}
		public String getId() {
			return id;
		}
		public void setId(String id) {
			this.id = id;
		}
		public String getLink() {
			return link;
		}
		public void setLink(String link) {
			this.link = link;
		}
		public String getEmailType() {
			return emailType;
		}
		public void setEmailType(String emailType) {
			this.emailType = emailType;
		}
		public String getDatabase() {
			return database;
		}
		public void setDatabase(String database) {
			this.database = database;
		}
		
		
	}

	



}
